package cn.com.main;

import cn.com.utils.FileUtil;
import cn.com.utils.MachineTranslationUtil;
import cn.hutool.core.collection.ConcurrentHashSet;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.server.PathContainer;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;

public class WebInterfaceScansAndGeneratesPermissions {


    public static final String TAB = "\t";
    public static final String STRING = ":";
    public static final String PREFIX = "E:\\cloud_star\\240911东莞大模型项目\\菜单接口\\";


    public static String MODULE = "订阅管理";
    public static String ROLE = "301";
    public static String MENU_CODE = "E01106";
    public static String CODE = "CBR";
    public static Set<String> MGT_IDS = new HashSet<>();
    public static Set<String> CONSOLE_IDS = new HashSet<>();

    public static void main(String[] args) throws IOException {

        // 示例数据
        List<String[]> date = Files.readAllLines(Paths.get(PREFIX + "input.txt"))
                .stream().map(line -> line.split(TAB)).collect(Collectors.toList());
        Set<String> fileNames = FileUtil.getFileName(PREFIX, "har");

        //generateAGroup(fileNames);

        StringBuilder result = new StringBuilder();
        fileNames.forEach(fileName -> {
            if (!fileName.contains("-")) {
                System.out.println("文件名不合法：" + fileName);
                return;
            }
            if (!fileName.contains("安全云脑-DG01.har")) {
                return;
            }
            String name = fileName.substring(0, fileName.lastIndexOf("."));
            String[] splitName = name.split("-");
            MODULE = splitName[0];
            MENU_CODE = splitName[1];
            CODE = splitName.length > 2 ? splitName[2] : MENU_CODE;
            ROLE = MENU_CODE.charAt(0) == 'C' || MENU_CODE.charAt(0) == 'D' ? "302" : "301";
            String operationName = MODULE;
            String str = generate(date, fileName, operationName);
            System.out.println(str);
            result.append(str);
            FileUtil.writeToFile(str, PREFIX + "output\\" + name + "-output.txt");
        });
        System.out.println("MGT_IDS：" + MGT_IDS.stream().reduce(getAccumulator()).orElse(""));
        System.out.println("CONSOLE_IDS：" + CONSOLE_IDS.stream().reduce(getAccumulator()).orElse(""));
        FileUtil.writeToFile(new TreeSet<>(List.of(result.toString().split("\n"))), PREFIX + "output\\" + "output.txt");
        System.out.println("\n\n-------------------------------");
    }

    private static void generateAGroup(Set<String> fileNames) {
        fileNames.forEach(fileName -> {
            String temp = "\n" +
                    "delete\n" +
                    "from sys_auth_action\n" +
                    "where auth_key in ('res:AIMS');\n" +
                    "\n" +
                    "INSERT INTO sys_auth_action (auth_key, auth_type, name, name_en, parent_auth_key, service_code, description,\n" +
                    "                             description_en, `sensitive`, created_by, created_dt, updated_by, updated_dt,\n" +
                    "                             version)\n" +
                    "VALUES ('res:AIMS', 'group', '模型集市', '', 'res', 'resource', '', '', null, null, null, null, null, null)\n" +
                    ";\n";

            String split = fileName.split("-")[1];
            String code = split.substring(0, split.lastIndexOf("."));

            System.out.print(temp.replaceAll("AIMS", code).replaceAll("模型集市", fileName.split("-")[0]));
            System.out.println("\n\n----------\n\n");
        });
    }

    /**
     * 获取累加器
     *
     * @return {@link BinaryOperator }<{@link String }>
     */
    @NotNull
    private static BinaryOperator<String> getAccumulator() {
        return (a, b) -> a.trim() + " , " + b.trim();
    }


    /**
     * 获取接口文件名
     *
     * @param directoryPath 目录路径
     * @param fileNames     文件名
     */
    private static void getInterfaceFileName(String directoryPath, Set<String> fileNames) {
        File directory = new File(directoryPath);

        // 使用匿名内部类作为文件名过滤器
        File[] harFiles = directory.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".har");
            }
        });

        if (harFiles != null) {
            for (File file : harFiles) {
                String fileName = file.getName();
                String interfaceFile = fileName.substring(0, fileName.lastIndexOf("."));
                fileNames.add(interfaceFile);
            }
        } else {
            System.out.println("提供的路径不是一个目录，或者目录是空的。");
        }
    }

    /**
     * 获取网址
     *
     * @param harFilePath har文件路径
     * @return {@link Set }<{@link String }>
     */
    public static Set<String> getUrls(String harFilePath) {
        return HarParser.parsingHarFile(harFilePath);
    }

    /**
     * 生成
     *
     * @param data          数据
     * @param interfaceFile 接口文件
     * @param operationName 操作名称
     * @return {@link String }
     */
    public static String generate(List<String[]> data, String interfaceFile, String operationName) {
        // 接口信息
        Set<String> urls = getUrls(PREFIX + interfaceFile);
        List<String[]> data1 = new ArrayList<>();
        List<String> ids = getIds(data, urls, data1, true);
        if (data1.isEmpty()) {
            System.out.println("没有找到匹配的接口信息");
            return "";
        }
        // 接口太多使用严格匹配
        if (ids.size() > 100) {
            data1 = new ArrayList<>();
            ids = getIds(data, urls, data1, true);
        }
        StringBuilder sqlBuilder = new StringBuilder();


        for (String[] value : data1) {
            //value =  11728370916595 	商品发布	POST	/api/v1/aimarket/shop	商品管理
            String id = value[0];
            String name = value[1];
            String method = value[2];
            String url = value[3];
            String module = value[4];
            //异步处理
            sqlBuilder.append(getTxt(name, MODULE, id)).append("\n");
        }
        String id = ids.stream().reduce(getAccumulator()).orElse("");
        sqlBuilder.append(getTxt(operationName, MODULE, id)).append("\n");
        if ("301".equals(ROLE)) {
            MGT_IDS.addAll(ids);
        } else {
            CONSOLE_IDS.addAll(ids);
        }
        // 清理缓存
        MODULE_IDS.clear();
        return sqlBuilder.toString();
    }

    @NotNull
    private static List<String> getIds(List<String[]> data, Set<String> urls, List<String[]> data1, boolean strictMatching) {
        List<String> ids = data.stream()
                .filter(arr -> strictMatching ? strictMatching(arr, urls) : isContains(arr, urls))
                .distinct()
                .peek(data1::add)
                .map(arr -> arr[0].trim())
                .distinct()
                .collect(Collectors.toList());
        return ids;
    }

    /**
     * 获取文本
     *
     * @param name   名称
     * @param module 模块
     * @param id     ID
     * @return {@link String }
     */
    private static String getTxt(String name, String module, String id) {
        // txt = 菜单编码 权限编码	权限类型	权限名称	英文名	父编码	业务模块	描述	描述英文	接口ID   角色ID
        String nameEn = turnToHump(MachineTranslationUtil.toEnglishByBaidu(name)).replace("'", "").trim();
        String moduleEn = turnToHump(MachineTranslationUtil.toEnglishByBaidu(module)).replace("'", "").trim();
        String privilegeCode = "res:" + CODE + STRING + (MODULE.equals(module) && name.equals(MODULE) ? "" : moduleEn + STRING) + nameEn;
        int endIndex = privilegeCode.lastIndexOf(STRING);
        return MENU_CODE + TAB
                + privilegeCode + TAB
                + "atom" + TAB
                + name + TAB
                + nameEn + TAB
                + privilegeCode.substring(0, endIndex < 0 ? privilegeCode.length() : endIndex) + TAB
                + "resource" + TAB
                + module + TAB
                + moduleEn + TAB
                + id + TAB
                + ROLE;
    }

    /**
     * 转向驼峰
     *
     * @param text 文本
     */
    private static String turnToHump(String text) {
        Set<String> stopWords = new HashSet<>(Arrays.asList("the", "is", "a", "to", "of", "in", "at", "on", "for", "with", "about", "an", "and", "or", "but", "it", "as", "this", "that"));

        String[] words = text.toLowerCase().split("\\s+");
        StringBuilder camelCase = new StringBuilder();

        for (int i = 0; i < words.length; i++) {
            if (!stopWords.contains(words[i])) {
                if (camelCase.length() == 0) {
                    camelCase.append(words[i]);
                } else {
                    camelCase.append(Character.toUpperCase(words[i].charAt(0)));
                    camelCase.append(words[i].substring(1));
                }
            }
        }
        return camelCase.toString();
    }

    public static Set<String> MODULE_IDS = new ConcurrentHashSet<>();

    /**
     * 是否包含 或者在同一模块
     *
     * @param arr  arr
     * @param urls 网址
     * @return boolean
     */
    private static boolean isContains(String[] arr, Set<String> urls) {
        return urls.stream().anyMatch(u -> {

            if (arr.length >= 5 && MODULE_IDS.contains(arr[4])) {
                return true;
            }
            if (arr.length < 5) {
                return false;
            }
            String[] split = u.split(TAB);
            boolean compareRequestPath = compareRequestPath(split[0], "https://mgt.aimarket.com/" + arr[3])
                    || compareRequestPath(split[0], "https://uconsole.aimarket.com/" + arr[3])
                    || compareRequestPath(split[0], "https://www.aimarket.com/" + arr[3]);
            boolean logicalMatching = compareRequestPath && arr[2].equalsIgnoreCase(split[1]);
            if (logicalMatching) {
                MODULE_IDS.add(arr[4]);
            }
            return logicalMatching;
        });
    }


    /**
     * 是否包含 或者在同一模块
     *
     * @param arr  arr
     * @param urls 网址
     * @return boolean
     */
    private static boolean strictMatching(String[] arr, Set<String> urls) {
        return urls.stream().anyMatch(u -> {
            if (arr.length < 5) {
                return false;
            }
            String[] split = u.split(TAB);
            boolean compareRequestPath = compareRequestPath(split[0], "https://mgt.aimarket.com/" + arr[3])
                    || compareRequestPath(split[0], "https://uconsole.aimarket.com/" + arr[3])
                    || compareRequestPath(split[0], "https://uconsole.dg-test-bsscmp.com/" + arr[3])
                    || compareRequestPath(split[0], "https://www.aimarket.com/" + arr[3]);
            boolean logicalMatching = compareRequestPath && arr[2].equalsIgnoreCase(split[1]);
            if (logicalMatching) {
                MODULE_IDS.add(arr[4]);
            }
            return logicalMatching;
        });
    }

    /**
     * 比较请求路径
     *
     * @param requestPath  请求路径
     * @param originalPath 原始路径
     * @return boolean
     */
    private static boolean compareRequestPath(String requestPath, String originalPath) {
        org.springframework.web.util.pattern.PathPattern parse = PathPatternParser.defaultInstance.parse(originalPath);
        PathPattern.PathMatchInfo pathMatchInfo = parse.matchAndExtract(PathContainer.parsePath(requestPath));
        if (Objects.isNull(pathMatchInfo) || Objects.isNull(pathMatchInfo.getUriVariables())) {
            return requestPath.contains(originalPath);
        }
        Map<String, String> uriVariables = pathMatchInfo.getUriVariables();
        for (Map.Entry<String, String> entry : uriVariables.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            String placeholder = "{" + key + "}";
            originalPath = originalPath.replace(placeholder, value);
        }
        return requestPath.contains(originalPath);
    }
}